package com.crawler.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.crawler.system.dto.CrawlerTaskDTO;
import com.crawler.system.entity.CrawlerResult;
import com.crawler.system.entity.CrawlerTask;
import com.crawler.system.entity.ProxyIp;
import com.crawler.system.repository.CrawlerResultRepository;
import com.crawler.system.repository.CrawlerTaskRepository;
import com.crawler.system.repository.ProxyIpRepository;
import com.crawler.system.service.CrawlerEngine;
import com.crawler.system.service.CrawlerService;
import com.crawler.system.util.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CompletableFuture;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 爬虫服务实现类
 */
@Slf4j
@Service
public class CrawlerServiceImpl implements CrawlerService {

    private final CrawlerTaskRepository taskRepository;
    private final CrawlerResultRepository resultRepository;
    private final ProxyIpRepository proxyIpRepository;
    private final BasicCrawlerEngine basicCrawlerEngine;
    private final DynamicCrawlerEngine dynamicCrawlerEngine;

    /**
     * 当前正在运行的爬虫任务引擎映射
     */
    private final Map<Long, CrawlerEngine> runningEngines = new ConcurrentHashMap<>();

    /**
     * 构造函数
     * 
     * @param taskRepository 爬虫任务仓库
     * @param resultRepository 爬虫结果仓库
     * @param proxyIpRepository 代理IP仓库
     * @param basicCrawlerEngine 基础爬虫引擎
     * @param dynamicCrawlerEngine 动态爬虫引擎
     */
    public CrawlerServiceImpl(
        CrawlerTaskRepository taskRepository,
        CrawlerResultRepository resultRepository,
        ProxyIpRepository proxyIpRepository,
        BasicCrawlerEngine basicCrawlerEngine,
        DynamicCrawlerEngine dynamicCrawlerEngine
    ) {
        this.taskRepository = taskRepository;
        this.resultRepository = resultRepository;
        this.proxyIpRepository = proxyIpRepository;
        this.basicCrawlerEngine = basicCrawlerEngine;
        this.dynamicCrawlerEngine = dynamicCrawlerEngine;
    }

    @Override
    @Transactional
    public Long createTask(CrawlerTask task) {
        // 设置默认值
        task.setStatus("PENDING");
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());

        // 获取当前用户ID
        Long userId = SecurityUtils.getCurrentUserId();
        task.setCreatedBy(userId);

        // 保存任务
        taskRepository.insert(task);
        return task.getId();
    }

    @Override
    @Transactional
    public boolean updateTask(CrawlerTask task) {
        CrawlerTask existingTask = taskRepository.selectById(task.getId());
        if (existingTask == null) {
            return false;
        }

        // 只有待执行状态的任务才能更新
        if (!"PENDING".equals(existingTask.getStatus()) && !"COMPLETED".equals(existingTask.getStatus()) && !"FAILED".equals(existingTask.getStatus())) {
            throw new IllegalStateException("只有待执行、已完成或失败的任务才能更新");
        }

        // 保留原有的一些字段值
        task.setCreatedBy(existingTask.getCreatedBy());
        task.setCreateTime(existingTask.getCreateTime());
        task.setLastExecuteTime(existingTask.getLastExecuteTime());
        task.setCompleteTime(existingTask.getCompleteTime());
        
        task.setUpdateTime(LocalDateTime.now());
        task.setStatus("PENDING"); // 更新后重置状态为待执行

        return taskRepository.updateById(task) > 0;
    }

    @Override
    @Transactional
    public boolean deleteTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            return false;
        }

        // 检查任务是否正在运行
        if ("RUNNING".equals(task.getStatus()) || "PAUSED".equals(task.getStatus())) {
            // 停止任务
            stopTask(taskId);
        }

        // 删除任务结果
        QueryWrapper<CrawlerResult> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_id", taskId);
        resultRepository.delete(queryWrapper);

        // 删除任务
        return taskRepository.deleteById(taskId) > 0;
    }

    @Override
    public CrawlerTaskDTO getTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            return null;
        }
        
        // 转换为DTO
        CrawlerTaskDTO dto = new CrawlerTaskDTO();
        BeanUtils.copyProperties(task, dto);
        
        // 获取创建人信息
        // 实际项目中应该从用户服务获取用户名
        dto.setCreatedByName("管理员");
        
        return dto;
    }

    @Override
    public List<CrawlerTask> listTasks(Map<String, Object> params) {
        QueryWrapper<CrawlerTask> queryWrapper = buildTaskQueryWrapper(params);
        return taskRepository.selectList(queryWrapper);
    }

    /**
     * 构建爬虫任务查询条件
     */
    private QueryWrapper<CrawlerTask> buildTaskQueryWrapper(Map<String, Object> params) {
        QueryWrapper<CrawlerTask> queryWrapper = new QueryWrapper<>();
        
        if (params != null) {
            // 按名称查询
            if (params.containsKey("name") && StringUtils.hasText((String) params.get("name"))) {
                queryWrapper.like("name", params.get("name"));
            }
            
            // 按状态查询
            if (params.containsKey("status") && StringUtils.hasText((String) params.get("status"))) {
                queryWrapper.eq("status", params.get("status"));
            }
            
            // 按爬虫类型查询
            if (params.containsKey("type") && params.get("type") != null) {
                queryWrapper.eq("type", params.get("type"));
            }
            
            // 按创建用户查询
            if (params.containsKey("createdBy") && params.get("createdBy") != null) {
                queryWrapper.eq("created_by", params.get("createdBy"));
            }
            
            // 按创建时间范围查询
            if (params.containsKey("startTime") && params.get("startTime") != null) {
                queryWrapper.ge("create_time", params.get("startTime"));
            }
            if (params.containsKey("endTime") && params.get("endTime") != null) {
                queryWrapper.le("create_time", params.get("endTime"));
            }
            
            // 排序
            String orderBy = (String) params.getOrDefault("orderBy", "create_time");
            String order = (String) params.getOrDefault("order", "desc");
            queryWrapper.orderBy(true, "asc".equalsIgnoreCase(order), orderBy);
        } else {
            // 默认按创建时间降序
            queryWrapper.orderByDesc("create_time");
        }
        
        return queryWrapper;
    }

    @Override
    @Transactional
    public List<Long> startTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            throw new IllegalArgumentException("爬虫任务不存在");
        }
        
        // 检查任务状态
        if ("RUNNING".equals(task.getStatus())) {
            throw new IllegalStateException("任务已在运行中");
        }
        
        // 检查是否暂停状态
        if ("PAUSED".equals(task.getStatus())) {
            // 恢复任务
            return resumeTask(taskId) ? Collections.emptyList() : Collections.emptyList();
        }
        
        // 初始化爬虫引擎
        CrawlerEngine engine;
        if (task.getType() == 2) { // 动态页面爬虫
            engine = dynamicCrawlerEngine;
        } else {
            engine = basicCrawlerEngine;
        }
        
        // 初始化引擎
        engine.init(task);
        
        // 设置代理IP
        if (task.getProxyEnabled() != null && task.getProxyEnabled()) {
            // 获取可用代理
            ProxyIp proxyIp = getAvailableProxy();
            if (proxyIp != null) {
                engine.setProxy(proxyIp);
            }
        }
        
        // 更新任务状态
        task.setStatus("RUNNING");
        task.setLastExecuteTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());
        taskRepository.updateById(task);
        
        // 将引擎添加到运行中的引擎映射
        runningEngines.put(taskId, engine);
        
        // 异步启动爬虫
        CompletableFuture.runAsync(() -> {
            try {
                List<Long> resultIds = engine.start();
                // 完成后清理
                runningEngines.remove(taskId);
            } catch (Exception e) {
                log.error("爬虫任务执行异常", e);
                engine.cleanup();
                runningEngines.remove(taskId);
            }
        });
        
        return Collections.emptyList(); // 实际结果会异步获取
    }

    /**
     * 获取可用代理IP
     */
    private ProxyIp getAvailableProxy() {
        QueryWrapper<ProxyIp> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "AVAILABLE");
        queryWrapper.orderByAsc("response_time");
        queryWrapper.last("LIMIT 1");
        return proxyIpRepository.selectOne(queryWrapper);
    }

    @Override
    public boolean stopTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            return false;
        }
        
        // 检查是否正在运行
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null) {
            engine.stop();
            engine.cleanup();
            runningEngines.remove(taskId);
        }
        
        // 更新任务状态
        if ("RUNNING".equals(task.getStatus()) || "PAUSED".equals(task.getStatus())) {
            task.setStatus("STOPPED");
            task.setUpdateTime(LocalDateTime.now());
            taskRepository.updateById(task);
        }
        
        return true;
    }

    @Override
    public boolean pauseTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            return false;
        }
        
        // 检查是否正在运行
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null && "RUNNING".equals(task.getStatus())) {
            engine.pause();
            
            // 更新任务状态
            task.setStatus("PAUSED");
            task.setUpdateTime(LocalDateTime.now());
            taskRepository.updateById(task);
            return true;
        }
        
        return false;
    }

    @Override
    public boolean resumeTask(Long taskId) {
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task == null) {
            return false;
        }
        
        // 检查是否暂停状态
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null && "PAUSED".equals(task.getStatus())) {
            engine.resume();
            
            // 更新任务状态
            task.setStatus("RUNNING");
            task.setUpdateTime(LocalDateTime.now());
            taskRepository.updateById(task);
            return true;
        }
        
        return false;
    }

    @Override
    public int getTaskProgress(Long taskId) {
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null) {
            return engine.getProgress();
        }
        
        // 如果引擎不存在，根据任务状态返回进度
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task != null) {
            switch (task.getStatus()) {
                case "COMPLETED":
                    return 100;
                case "PENDING":
                case "STOPPED":
                case "FAILED":
                    return 0;
                default:
                    return 0;
            }
        }
        
        return 0;
    }

    @Override
    public String getTaskStatus(Long taskId) {
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null) {
            return engine.getStatus();
        }
        
        // 如果引擎不存在，从数据库获取状态
        CrawlerTask task = taskRepository.selectById(taskId);
        return task != null ? task.getStatus() : "UNKNOWN";
    }

    @Override
    public Map<String, Object> getTaskStatistics(Long taskId) {
        Map<String, Object> statistics = new HashMap<>();
        
        // 从运行中的引擎获取统计信息
        CrawlerEngine engine = runningEngines.get(taskId);
        if (engine != null) {
            return engine.getStatistics();
        }
        
        // 从数据库获取统计信息
        CrawlerTask task = taskRepository.selectById(taskId);
        if (task != null) {
            // 获取结果数量
            QueryWrapper<CrawlerResult> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("task_id", taskId);
            long totalResults = resultRepository.selectCount(queryWrapper);
            
            // 获取成功结果数量
            queryWrapper.clear();
            queryWrapper.eq("task_id", taskId);
            queryWrapper.eq("process_status", "PROCESSED");
            long successResults = resultRepository.selectCount(queryWrapper);
            
            // 获取失败结果数量
            queryWrapper.clear();
            queryWrapper.eq("task_id", taskId);
            queryWrapper.eq("process_status", "FAILED");
            long failedResults = resultRepository.selectCount(queryWrapper);
            
            // 计算总数据大小
            queryWrapper.clear();
            queryWrapper.eq("task_id", taskId);
            queryWrapper.select("SUM(content_size) as total_size");
            Map<String, Object> resultMap = resultRepository.selectMaps(queryWrapper).get(0);
            Long totalSize = resultMap.get("total_size") != null ? ((Number) resultMap.get("total_size")).longValue() : 0L;
            
            // 计算执行时间
            long duration = 0;
            if (task.getLastExecuteTime() != null) {
                LocalDateTime endTime = task.getCompleteTime() != null ? task.getCompleteTime() : LocalDateTime.now();
                duration = java.time.Duration.between(task.getLastExecuteTime(), endTime).toMillis();
            }
            
            // 组装统计信息
            statistics.put("totalUrls", totalResults);
            statistics.put("successUrls", successResults);
            statistics.put("failedUrls", failedResults);
            statistics.put("totalSize", totalSize);
            statistics.put("duration", duration);
            statistics.put("status", task.getStatus());
        }
        
        return statistics;
    }

    @Override
    public List<CrawlerResult> listTaskResults(Long taskId, Map<String, Object> params) {
        QueryWrapper<CrawlerResult> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_id", taskId);
        
        if (params != null) {
            // 按状态筛选
            if (params.containsKey("processStatus") && StringUtils.hasText((String) params.get("processStatus"))) {
                queryWrapper.eq("process_status", params.get("processStatus"));
            }
            
            // 按URL筛选
            if (params.containsKey("sourceUrl") && StringUtils.hasText((String) params.get("sourceUrl"))) {
                queryWrapper.like("source_url", params.get("sourceUrl"));
            }
            
            // 按标题筛选
            if (params.containsKey("title") && StringUtils.hasText((String) params.get("title"))) {
                queryWrapper.like("title", params.get("title"));
            }
            
            // 排序
            String orderBy = (String) params.getOrDefault("orderBy", "create_time");
            String order = (String) params.getOrDefault("order", "desc");
            queryWrapper.orderBy(true, "asc".equalsIgnoreCase(order), orderBy);
        } else {
            // 默认按创建时间排序
            queryWrapper.orderByDesc("create_time");
        }
        
        return resultRepository.selectList(queryWrapper);
    }

    @Override
    public CrawlerResult getTaskResult(Long resultId) {
        return resultRepository.selectById(resultId);
    }

    @Override
    public String exportTaskResults(Long taskId, String exportType, List<Long> resultIds) {
        try {
            // 查询结果
            QueryWrapper<CrawlerResult> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("task_id", taskId);
            if (resultIds != null && !resultIds.isEmpty()) {
                queryWrapper.in("id", resultIds);
            }
            List<CrawlerResult> results = resultRepository.selectList(queryWrapper);
            
            if (results.isEmpty()) {
                return null;
            }
            
            // 确保导出目录存在
            String exportDir = "exports";
            Files.createDirectories(Paths.get(exportDir));
            
            // 获取任务信息
            CrawlerTask task = taskRepository.selectById(taskId);
            String taskName = task != null ? task.getName() : "task_" + taskId;
            String fileName = taskName.replaceAll("[^a-zA-Z0-9_-]", "_") + "_" + System.currentTimeMillis();
            String filePath = exportDir + File.separator + fileName;
            
            // 根据导出类型执行不同的导出操作
            switch (exportType.toUpperCase()) {
                case "CSV":
                    return exportToCsv(results, filePath + ".csv");
                case "EXCEL":
                    return exportToExcel(results, filePath + ".xlsx");
                case "JSON":
                    return exportToJson(results, filePath + ".json");
                default:
                    throw new IllegalArgumentException("不支持的导出类型: " + exportType);
            }
        } catch (Exception e) {
            log.error("导出任务结果失败", e);
            return null;
        }
    }
    
    /**
     * 导出为CSV格式
     */
    private String exportToCsv(List<CrawlerResult> results, String filePath) throws Exception {
        StringBuilder csv = new StringBuilder();
        
        // 添加表头
        csv.append("ID,源URL,标题,状态码,内容类型,内容大小,爬取深度,处理状态,创建时间\n");
        
        // 添加数据行
        for (CrawlerResult result : results) {
            csv.append(result.getId()).append(",");
            csv.append(escapeCsv(result.getSourceUrl())).append(",");
            csv.append(escapeCsv(result.getTitle())).append(",");
            csv.append(result.getStatusCode()).append(",");
            csv.append(escapeCsv(result.getContentType())).append(",");
            csv.append(result.getContentSize()).append(",");
            csv.append(result.getDepth()).append(",");
            csv.append(escapeCsv(result.getProcessStatus())).append(",");
            csv.append(result.getCreateTime()).append("\n");
        }
        
        // 写入文件
        Files.write(Paths.get(filePath), csv.toString().getBytes(StandardCharsets.UTF_8));
        return filePath;
    }
    
    /**
     * CSV字段转义
     */
    private String escapeCsv(String value) {
        if (value == null) {
            return "";
        }
        // 如果包含逗号、双引号或换行符，则用双引号包裹并将内部双引号转义
        if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
            return "\"" + value.replace("\"", "\"\"") + "\"";
        }
        return value;
    }
    
    /**
     * 导出为Excel格式
     */
    private String exportToExcel(List<CrawlerResult> results, String filePath) throws Exception {
        Workbook workbook = new XSSFWorkbook();
        org.apache.poi.ss.usermodel.Sheet sheet = workbook.createSheet("爬虫结果");
        
        // 创建表头
        org.apache.poi.ss.usermodel.Row headerRow = sheet.createRow(0);
        String[] headers = {"ID", "源URL", "标题", "状态码", "内容类型", "内容大小", "爬取深度", "处理状态", "创建时间"};
        for (int i = 0; i < headers.length; i++) {
            headerRow.createCell(i).setCellValue(headers[i]);
        }
        
        // 添加数据行
        int rowNum = 1;
        for (CrawlerResult result : results) {
            org.apache.poi.ss.usermodel.Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(result.getId());
            row.createCell(1).setCellValue(result.getSourceUrl());
            row.createCell(2).setCellValue(result.getTitle());
            row.createCell(3).setCellValue(result.getStatusCode());
            row.createCell(4).setCellValue(result.getContentType());
            row.createCell(5).setCellValue(result.getContentSize());
            row.createCell(6).setCellValue(result.getDepth());
            row.createCell(7).setCellValue(result.getProcessStatus());
            row.createCell(8).setCellValue(result.getCreateTime().toString());
        }
        
        // 写入文件
        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
        } finally {
            workbook.close();
        }
        
        return filePath;
    }
    
    /**
     * 导出为JSON格式
     */
    private String exportToJson(List<CrawlerResult> results, String filePath) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
        objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        
        // 写入文件
        objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File(filePath), results);
        return filePath;
    }
} 
